import javax.media.j3d.Appearance;
import javax.media.j3d.BranchGroup;
import javax.media.j3d.ColoringAttributes;
import javax.media.j3d.LineArray;
import javax.media.j3d.Shape3D;
import javax.media.j3d.Transform3D;
import javax.media.j3d.TransformGroup;
import javax.vecmath.Color3f;
import javax.vecmath.Point3f;
import javax.vecmath.Vector2f;
import javax.vecmath.Vector3f;


public class Particle {
	private static final float COLOR_DECAY = 0.5f;
	
	public BranchGroup BG;
	
	public Vector2f position;
	public Vector2f velocity;
	
	public Color3f color;
	private boolean should_delete;
	
	private float orientation;
	private float angular_velocity;
	
	private float my_color_decay;
	
	private Shape3D dot;
	private Appearance app;
	
	private TransformGroup TG;
	private Transform3D T3D;
	
	public Particle(float positionX, float positionY, float velocityX,
			float velocityY, Color3f color)
	{
		this.color = color;
		should_delete = false;
		position = new Vector2f(positionX, positionY);
		velocity = new Vector2f(velocityX, velocityY);
		
		orientation = (float)(Math.PI * Math.random());
		angular_velocity = 10f*(float)(Math.random() - 0.5);
		
		my_color_decay = COLOR_DECAY + ((COLOR_DECAY/1f) * (float)(Math.random() - 0.5));
		
		app = new Appearance();
		app.setCapability(Appearance.ALLOW_COLORING_ATTRIBUTES_WRITE);
		app.setColoringAttributes(new ColoringAttributes(color, 
				ColoringAttributes.SHADE_FLAT));
		
		BG = new BranchGroup();
		BG.setCapability(BranchGroup.ALLOW_DETACH);
		
		TG = new TransformGroup();
		TG.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
		BG.addChild(TG);
		
		T3D = new Transform3D();
		
		createShape();
	}
	
	public void updateState(float duration) 
	{
		float dec = duration * my_color_decay;
		float red = (color.x - dec < 0) ? 0 : color.x - dec;
		float green = (color.y - dec < 0) ? 0 : color.y - dec;
		float blue = (color.z - dec < 0) ? 0 : color.z - dec;
		color = new Color3f(red, green, blue);
		
		if(0 == red && 0 == green && 0 == blue)
				should_delete = true;
		
		
		app.setColoringAttributes(new ColoringAttributes(color, 
				ColoringAttributes.SHADE_FLAT));
		dot.setAppearance(app);
		
		position.scaleAdd(duration, velocity, position);
		orientation += angular_velocity * duration;
	}
	
	public void updateTransformGroup() 
	{
		T3D.rotZ(orientation);
		T3D.setTranslation(new Vector3f(position.x,position.y,0));
		TG.setTransform(T3D);
	}
	
	public boolean shouldDelete() 
	{
		return should_delete;
	}
	
	private void createShape() 
	{
		Appearance app = new Appearance();
		ColoringAttributes ca = new ColoringAttributes(color,
				ColoringAttributes.SHADE_FLAT);
		app.setColoringAttributes(ca);
		
		Point3f[] points = new Point3f[2];
		points[0] = new Point3f(0,0,0);
		points[1] = new Point3f(0,randomWidth(),0);
		
		LineArray pla = new LineArray(2, LineArray.COORDINATES);
		pla.setCoordinates(0, points);
		dot = new Shape3D(pla, app);
		dot.setCapability(Shape3D.ALLOW_APPEARANCE_WRITE);
		
		TG.addChild(dot);
		
		BranchGroup root = new BranchGroup();
		root.setCapability(BranchGroup.ALLOW_DETACH);
		root.setCapability(BranchGroup.ALLOW_BOUNDS_WRITE);
		root.setCapability(BranchGroup.ALLOW_CHILDREN_EXTEND);
	}
	
	private float randomWidth() {
		final float min = 0.05f;
		final float max = 0.25f;
		
		float r = max * (float)Math.random();
		return (r >= min) ? r : min;
	}
}
